
const fs = require('fs'),
  path = require('path'),
  BASE_REM = 1 / 14,
  antDesignStyleRootPath = path.resolve(process.cwd(), 'node_modules/ant-design-vue/es'),
  lessFiles = [],
  options = {}
// options = {
//   mainLessFile: 'framework/styles/index.less',
//   replaceVars: {
//     '@font-size-base': '1rem'
//   }
// }

// 参与运算的变量
let variables = {},
  // 被关联的变量
  referenced_vars = []

function px2rem (px) {
  return `${(parseInt(px) * BASE_REM).toFixed(8)}rem`
}

function getVarsInLessFiles (filepath) {
  if (!fs.existsSync(filepath.replace('.less', '.less.o'))) {
    // 备份 less 文件
    fs.copyFileSync(filepath, filepath.replace('.less', '.less.o'))
  }
  const dirname = path.dirname(filepath),
    lessFile = {
      filepath: filepath.replace('.less', '.less.o'),
      content: fs.readFileSync(filepath.replace('.less', '.less.o'), 'utf8'),
      lines: []
    }

  const lines = lessFile.content.split('\n').map((line, index) => {
    if (/^(\s+)?@import\s+/.test(line)) {
      // 以 @import 开头的行为引入文件
      let import_file = line.match(/['"](.+)['"]/)?.[1]
      if (!import_file || import_file.startsWith('~ant-design-vue')) {
        return
      }
      if (import_file.startsWith('~')) {
        import_file = import_file.substring(1)
      }
      if (import_file.startsWith('@')) {
        import_file = `node_modules/${import_file}`
        return getVarsInLessFiles(path.resolve(process.cwd(), import_file))
      }
      return getVarsInLessFiles(path.resolve(dirname, import_file))
      // 以 @ 开头的行为定义变量
    } else if ((/^(\s+)?@[a-z-]+?/).test(line)) {
      let k = line.trim().match(/^@?[a-z0-9-]+:\s?/)?.[0]
      if (!k) {
        return
      }
      let v = line.split(':')[1].trim()
      k = k.trim()
      k = k.substring(0, k.length - 1)
      // 如果 v 中含有对px的运算，则提取 v 中的变量
      v.match(/@[a-z0-9-]+/gi)?.forEach(m => {
        referenced_vars.indexOf(m) === -1 && referenced_vars.push(m)
      })
      if ((/^@[a-z-]+?/).test(k)) {
        variables[k] = v.substring(0, v.length - 1)
      }
      if ((/[+\-\*\/]\s\d+px/g).test(v) && v.indexOf('@') !== -1) {
        // 如果 v 中含有对px的运算，则缓存当前行
        return { text: line, lineIndex: index }
      }
    }
  }).filter(l => !!l)
  lines.length > 0 && lessFiles.push({ ...lessFile, lines })
}

function getAntDesignLess (dir) {
  dir = dir || antDesignStyleRootPath
  fs.readdirSync(dir).forEach(f => {
    const stat = fs.statSync(path.join(dir, f))
    if (path.join(dir, f).indexOf('assets') !== -1) {
      return
    }
    if (f.endsWith('.less')) {
      let lessFile = null
      if (!fs.existsSync(path.join(dir, f.replace('.less', '.less.o')))) {
        // 备份 less 文件
        fs.copyFileSync(path.join(dir, f), path.join(dir, f.replace('.less', '.less.o')))
      }
      lessFile = {
        filepath: path.join(dir, f.replace('.less', '.less.o')),
        content: fs.readFileSync(path.join(dir, f.replace('.less', '.less.o')), 'utf8')
      }
      const lines = lessFile.content.split('\n').map((line, index) => {
        let k = line.trim().match(/^@?[a-z0-9-]+:\s?/)?.[0]
        if (!k) {
          return
        }
        let v = line.split(':')[1].trim()
        k = k.trim()
        k = k.substring(0, k.length - 1)
        if (options.replaceVars[k]) {
          // 替换变量
          return { text: line, lineIndex: index }
        }
        // 如果 v 中含有对px的运算，则提取 v 中的变量
        v.match(/@[a-z0-9-]+/gi)?.forEach(m => {
          referenced_vars.indexOf(m) === -1 && referenced_vars.push(m)
        })
        if ((/^@[a-z-]+?/).test(k)) {
          // 以 @ 开头的行为定义变量
          variables[k] = v.substring(0, v.length - 1)
        }
        if ((/[+\-\*\/]\s\d+px/g).test(v) && v.indexOf('@') !== -1) {
          // 如果 v 中含有对px的运算，则缓存当前行
          return { text: line, lineIndex: index }
        }
      }).filter(l => !!l)
      lines.length > 0 && lessFiles.push({ ...lessFile, lines })
    } else if (stat.isDirectory()) {
      getAntDesignLess(path.join(dir, f))
    }
  })
}

/**
 * 查找并替换变量
 */
function findReferenceVariable (varname, temp_referenced_vars) {
  let varvalue = variables[varname],
    matches = varvalue?.match(/@[a-z0-9-]+/gi)
  if (!matches) {
    return
  }
  matches.forEach(m => {
    if (temp_referenced_vars.indexOf(m) === -1) {
      temp_referenced_vars.push(m)
      findReferenceVariable(m, temp_referenced_vars)
    }
  })
}

/**
 * 重建 less 文件
 */
module.exports = function (_options) {
  Object.assign(options, _options)

  getAntDesignLess()

  getVarsInLessFiles(path.join(process.cwd(), options.mainLessFile))

  // 基准变量
  variables['@font-size-sm'] = `@font-size-base - 2px`

  // 替换变量
  Object.assign(variables, options.replaceVars)

  // 过滤出来的与 font-size-base 有直接或间接关系的所有变量
  let filtered_vars = Object.keys(options.replaceVars)

  referenced_vars.forEach(varname => {
    let temp_referenced_vars = []
    findReferenceVariable(varname, temp_referenced_vars)
    if (temp_referenced_vars.find(vname => filtered_vars.indexOf(vname) !== -1)) {
      filtered_vars = Array.from(new Set([...filtered_vars, ...temp_referenced_vars]))
    }
  })

  lessFiles.forEach((lessFile, _index) => {
    // 替换与过滤出来的变量相关的运算的计算单位
    lessFile.replaceLines = {}

    lessFile.lines.forEach((line, index) => {
      const text = line.text.trim()
      let key = text.match(/^@?[a-z0-9-]+:\s/)?.[0]
      if (!key) {
        return
      }

      let value = text.replace(key, ''),
        matche_vars = value.match(/@[a-z0-9-]+/gi)

      if (options.replaceVars[key.replace(':', '').trim()]) {
        value = value.trim()
        line.newText = line.text.replace(value, `${options.replaceVars[key.replace(':', '').trim()]};`)
        lessFile.content = lessFile.content.split('\n')
        lessFile.content.splice(line.lineIndex, 1, line.newText)
        lessFile.content = lessFile.content.join('\n')
        return
      }

      if (!(/[+-]\s\d+px/g).test(value)) {
        return
      }
      if (!matche_vars || matche_vars.find(v => filtered_vars.indexOf(v) === -1)) {
        return
      }
      let matches = value.match(/\s\d+px/gi),
        n_value = value
      if (!matches) {
        return
      }
      matches.forEach(m => {
        n_value = n_value.replace(m, m.replace(/\d+px/, `${px2rem(m)}`))
      })
      line.newText = line.text.replace(value, n_value)
      lessFile.content = lessFile.content.split('\n')
      lessFile.content.splice(line.lineIndex, 1, line.newText)
      lessFile.content = lessFile.content.join('\n')
      // console.log(lessFile.content)
    })
    fs.writeFileSync(lessFile.filepath.replace('.o', ''), lessFile.content)
  })

  console.log('重建 less 文件完成')
}